#pragma once
#include <vector>
#include <queue>
#include <memory>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <future>
#include <functional>
#include <stdexcept>
using namespace std;

class ThreadPool
{
public:
    ThreadPool(size_t threads);
    ~ThreadPool();

    // 禁止拷贝构造和赋值
    ThreadPool(const ThreadPool &) = delete;
    ThreadPool &operator=(const ThreadPool &) = delete;

    // 提交任务到线程池
    template <class F, class... Args>
    auto enqueue(F &&f, Args &&...args)
        -> future<typename result_of<F(Args...)>::type>;

private:
    // 工作线程集合
    vector<thread> workers;
    // 任务队列
    queue<function<void()>> tasks;

    // 同步原语
    mutex queueMutex;
    condition_variable condition;
    bool stop;
};

// 模板函数实现
template <class F, class... Args>
auto ThreadPool::enqueue(F &&f, Args &&...args)
    -> future<typename result_of<F(Args...)>::type>
{
    using return_type = typename result_of<F(Args...)>::type;

    auto task = make_shared<packaged_task<return_type()>>(
        bind(forward<F>(f), forward<Args>(args)...));

    future<return_type> res = task->get_future();
    {
        unique_lock<mutex> lock(queueMutex);
        // 不允许在线程池停止后添加新任务
        if (stop)
            throw runtime_error("enqueue on stopped ThreadPool");
        tasks.emplace([task]()
                      { (*task)(); });
    }
    condition.notify_one();
    return res;
}